home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 January / enter-2004-01.iso / files / maxima-5.9.0.exe / {app} / share / maxima / 5.9.0 / src / nregex.lisp < prev    next >
Encoding:
Text File  |  2003-02-09  |  20.1 KB  |  533 lines

  1. ;;; -*- Mode: Lisp; Package:USER; Base:10 -*-
  2. ;;;
  3. ;;; This code was written by:
  4. ;;;
  5. ;;;    Lawrence E. Freil <lef@nscf.org>
  6. ;;;    National Science Center Foundation
  7. ;;;    Augusta, Georgia 30909
  8. ;;;
  9. ;;; If you modify this code, please comment your modifications
  10. ;;; clearly and inform the author of any improvements so they
  11. ;;; can be incorporated in future releases.
  12. ;;;
  13. ;;; nregex.lisp - My 4/8/92 attempt at a Lisp based regular expression
  14. ;;;               parser. 
  15. ;;;
  16. ;;;               This regular expression parser operates by taking a
  17. ;;;               regular expression and breaking it down into a list
  18. ;;;               consisting of lisp expressions and flags.  The list
  19. ;;;               of lisp expressions is then taken in turned into a
  20. ;;;               lambda expression that can be later applied to a
  21. ;;;               string argument for parsing.
  22.  
  23. ;;;
  24. ;;; First we create a copy of macros to help debug the beast
  25.  
  26. (eval-when (:compile-toplevel :load-toplevel :execute)
  27. (defpackage "NREGEX"
  28.   (:use "COMMON-LISP")
  29.   (:export
  30.    ;; Vars
  31.    "*REGEX-DEBUG*" "*REGEX-GROUPS*" "*REGEX-GROUPINGS*"
  32.    ;; Functions
  33.    "REGEX-COMPILE"
  34.    ))
  35. )
  36.  
  37. (in-package "NREGEX")
  38.  
  39. (eval-when (:compile-toplevel :load-toplevel :execute)
  40. (defvar *regex-debug* nil)        ; Set to nil for no debugging code
  41.  
  42. (defmacro info (message &rest args)
  43.   (if *regex-debug*
  44.       `(format *trace-output* ,message ,@args)))
  45.  
  46. ;;;
  47. ;;; Declare the global variables for storing the paren index list.
  48. ;;;
  49. (defvar *regex-groups* (make-array 10))
  50. (defvar *regex-groupings* 0)
  51. )
  52.  
  53. ;;;
  54. ;;; Declare a simple interface for testing.  You probably wouldn't want
  55. ;;; to use this interface unless you were just calling this once.
  56. ;;;
  57. (defun regex (expression string)
  58.   "Usage: (regex <expression> <string)
  59.    This function will call regex-compile on the expression and then apply
  60.    the string to the returned lambda list."
  61.   (let ((findit (cond ((stringp expression)
  62.                (regex-compile expression))
  63.               ((listp expression)
  64.                expression)))
  65.     (result nil))
  66.     (if (not (funcall (if (functionp findit)
  67.               findit
  68.             (eval `(function ,findit))) string))
  69.     (return-from regex nil))
  70.     (if (= *regex-groupings* 0)
  71.     (return-from regex t))
  72.     (dotimes (i *regex-groupings*)
  73.       (push (funcall 'subseq 
  74.              string 
  75.              (car (aref *regex-groups* i))
  76.              (cadr (aref *regex-groups* i)))
  77.         result))
  78.     (reverse result)))
  79. ;;;
  80. ;;; Declare some simple macros to make the code more readable.
  81. ;;;
  82. (defvar *regex-special-chars* "?*+.()[]\\${}")
  83.  
  84. (defmacro add-exp (list)
  85.   "Add an item to the end of expression"
  86.   `(setf expression (append expression ,list)))
  87.  
  88. ;;;
  89. ;;; Now for the main regex compiler routine.
  90. ;;;
  91. (defun regex-compile (source &key (anchored nil) (case-sensitive t))
  92.   "Usage: (regex-compile <expression> [ :anchored (t/nil) ] [ :case-sensitive (t/nil) ])
  93.        This function take a regular expression (supplied as source) and
  94.        compiles this into a lambda list that a string argument can then
  95.        be applied to.  It is also possible to compile this lambda list
  96.        for better performance or to save it as a named function for later
  97.        use"
  98.   (info "Now entering regex-compile with \"~A\"~%" source)
  99.   ;;
  100.   ;; This routine works in two parts.
  101.   ;; The first pass take the regular expression and produces a list of 
  102.   ;; operators and lisp expressions for the entire regular expression.  
  103.   ;; The second pass takes this list and produces the lambda expression.
  104.   (let ((expression '())        ; holder for expressions
  105.     (group 1)            ; Current group index
  106.     (group-stack nil)        ; Stack of current group endings
  107.     (result nil)            ; holder for built expression.
  108.     (fast-first nil))        ; holder for quick unanchored scan
  109.     ;;
  110.     ;; If the expression was an empty string then it alway
  111.     ;; matches (so lets leave early)
  112.     ;;
  113.     (if (= (length source) 0)
  114.     (return-from regex-compile
  115.              '(lambda (&rest args)
  116.             (declare (ignore args))
  117.             t)))
  118.     ;;
  119.     ;; If the first character is a caret then set the anchored
  120.     ;; flags and remove if from the expression string.
  121.     ;;
  122.     (cond ((eql (char source 0) #\^)
  123.        (setf source (subseq source 1))
  124.        (setf anchored t)))
  125.     ;;
  126.     ;; If the first sequence is .* then also set the anchored flags.
  127.     ;; (This is purely for optimization, it will work without this).
  128.     ;;
  129.     (if (>= (length source) 2)
  130.     (if (string= source ".*" :start1 0 :end1 2)
  131.         (setf anchored t)))
  132.     ;;
  133.     ;; Also, If this is not an anchored search and the first character is
  134.     ;; a literal, then do a quick scan to see if it is even in the string.
  135.     ;; If not then we can issue a quick nil, 
  136.     ;; otherwise we can start the search at the matching character to skip
  137.     ;; the checks of the non-matching characters anyway.
  138.     ;;
  139.     ;; If I really wanted to speed up this section of code it would be 
  140.     ;; easy to recognize the case of a fairly long multi-character literal
  141.     ;; and generate a Boyer-Moore search for the entire literal. 
  142.     ;;
  143.     ;; I generate the code to do a loop because on CMU Lisp this is about
  144.     ;; twice as fast a calling position.
  145.     ;;
  146.     (if (and (not anchored)
  147.          (not (position (char source 0) *regex-special-chars*))
  148.          (not (and (> (length source) 1)
  149.                (position (char source 1) *regex-special-chars*))))
  150.     (setf fast-first `((if (not (do ((i start (+ i 1)))
  151.                     ((>= i length))
  152.                       (if (,(if case-sensitive 'eql 'char-equal)
  153.                         (char string i)
  154.                         ,(char source 0))
  155.                       (return (setf start i)))))
  156.                   (return-from final-return nil)))))
  157.     ;;
  158.     ;; Generate the very first expression to save the starting index
  159.     ;; so that group 0 will be the entire string matched always
  160.     ;;
  161.     (add-exp '((setf (aref *regex-groups* 0)
  162.              (list index nil))))
  163.     ;;
  164.     ;; Loop over each character in the regular expression building the
  165.     ;; expression list as we go.
  166.     ;;
  167.     (do ((eindex 0 (1+ eindex)))
  168.     ((= eindex (length source)))
  169.       (let ((current (char source eindex)))
  170.     (info "Now processing character ~A index = ~A~%" current eindex)
  171.     (case current
  172.       ((#\.)
  173.        ;;
  174.        ;; Generate code for a single wild character
  175.        ;;
  176.        (add-exp '((if (>= index length)
  177.               (return-from compare nil)
  178.             (incf index)))))
  179.       ((#\$)
  180.        ;;
  181.        ;; If this is the last character of the expression then
  182.        ;; anchor the end of the expression, otherwise let it slide
  183.        ;; as a standard character (even though it should be quoted).
  184.        ;;
  185.        (if (= eindex (1- (length source)))
  186.            (add-exp '((if (not (= index length))
  187.                   (return-from compare nil))))
  188.          (add-exp '((if (not (and (< index length)
  189.                       (eql (char string index) #\$)))
  190.                 (return-from compare nil)
  191.               (incf index))))))
  192.       ((#\*)
  193.        (add-exp '(ASTRISK)))
  194.  
  195.       ((#\+)
  196.        (add-exp '(PLUS)))
  197.  
  198.       ((#\?)
  199.        (add-exp '(QUESTION)))
  200.  
  201.       ((#\()
  202.        ;;
  203.        ;; Start a grouping.
  204.        ;;
  205.        (incf group)
  206.        (push group group-stack)
  207.        (add-exp `((setf (aref *regex-groups* ,(1- group)) 
  208.                 (list index nil))))
  209.        (add-exp `(,group)))
  210.       ((#\))
  211.        ;;
  212.        ;; End a grouping
  213.        ;;
  214.        (let ((group (pop group-stack)))
  215.          (add-exp `((setf (cadr (aref *regex-groups* ,(1- group)))
  216.                   index)))
  217.          (add-exp `(,(- group)))))
  218.       ((#\[)
  219.        ;;
  220.        ;; Start of a range operation.
  221.        ;; Generate a bit-vector that has one bit per possible character
  222.        ;; and then on each character or range, set the possible bits.
  223.        ;;
  224.        ;; If the first character is carat then invert the set.
  225.        (let* ((invert (eql (char source (1+ eindex)) #\^))
  226.           (bitstring (make-array 256 :element-type 'bit
  227.                          :initial-element
  228.                             (if invert 1 0)))
  229.           (set-char (if invert 0 1)))
  230.          (if invert (incf eindex))
  231.          (do ((x (1+ eindex) (1+ x)))
  232.          ((eql (char source x) #\]) (setf eindex x))
  233.            (info "Building range with character ~A~%" (char source x))
  234.            (cond ((and (eql (char source (1+ x)) #\-)
  235.                (not (eql (char source (+ x 2)) #\])))
  236.               (if (>= (char-code (char source x))
  237.                  (char-code (char source (+ 2 x))))
  238.               (error "Invalid range \"~A-~A\".  Ranges must be in acending order"
  239.                  (char source x) (char source (+ 2 x))))
  240.               (do ((j (char-code (char source x)) (1+ j)))
  241.                ((> j (char-code (char source (+ 2 x))))
  242.             (incf x 2))
  243.              (info "Setting bit for char ~A code ~A~%" (code-char j) j)
  244.              (setf (sbit bitstring j) set-char)))
  245.              (t
  246.               (cond ((not (eql (char source x) #\]))
  247.                  (let ((char (char source x)))
  248.                    ;;
  249.                    ;; If the character is quoted then find out what
  250.                    ;; it should have been
  251.                    ;;
  252.                    (if (eql (char source x) #\\ )
  253.                    (let ((length))
  254.                      (multiple-value-setq (char length)
  255.                      (regex-quoted (subseq source x) invert))
  256.                      (incf x length)))
  257.                    (info "Setting bit for char ~A code ~A~%" char (char-code char))
  258.                    (if (not (vectorp char))
  259.                    (setf (sbit bitstring (char-code (char source x))) set-char)
  260.                  (bit-ior bitstring char t))))))))
  261.          (add-exp `((let ((range ,bitstring))
  262.               (if (>= index length)
  263.                   (return-from compare nil))
  264.               (if (= 1 (sbit range (char-code (char string index))))
  265.                   (incf index)
  266.                 (return-from compare nil)))))))
  267.       ((#\\ )
  268.        ;;
  269.        ;; Intreprete the next character as a special, range, octal, group or 
  270.            ;; just the character itself.
  271.        ;;
  272.        (let ((length)
  273.          (value))
  274.          (multiple-value-setq (value length)
  275.          (regex-quoted (subseq source (1+ eindex)) nil))
  276.          (cond ((listp value)
  277.             (add-exp value))
  278.            ((characterp value)
  279.             (add-exp `((if (not (and (< index length)
  280.                          (eql (char string index) 
  281.                           ,value)))
  282.                    (return-from compare nil)
  283.                  (incf index)))))
  284.            ((vectorp value)
  285.             (add-exp `((let ((range ,value))
  286.                  (if (>= index length)
  287.                      (return-from compare nil))
  288.                  (if (= 1 (sbit range (char-code (char string index))))
  289.                      (incf index)
  290.                    (return-from compare nil)))))))
  291.          (incf eindex length)))
  292.       (t
  293.        ;;
  294.        ;; We have a literal character.  
  295.        ;; Scan to see how many we have and if it is more than one
  296.        ;; generate a string= verses as single eql.
  297.        ;;
  298.        (let* ((lit "")
  299.           (term (dotimes (litindex (- (length source) eindex) nil)
  300.               (let ((litchar (char source (+ eindex litindex))))
  301.                 (if (position litchar *regex-special-chars*)
  302.                 (return litchar)
  303.                   (progn
  304.                 (info "Now adding ~A index ~A to lit~%" litchar 
  305.                       litindex)
  306.                 (setf lit (concatenate 'string lit 
  307.                                (string litchar)))))))))
  308.          (if (= (length lit) 1)
  309.          (add-exp `((if (not (and (< index length)
  310.                       (,(if case-sensitive 'eql 'char-equal)
  311.                        (char string index) ,current)))
  312.                 (return-from compare nil)
  313.                   (incf index))))
  314.            ;;
  315.            ;; If we have a multi-character literal then we must
  316.            ;; check to see if the next character (if there is one)
  317.            ;; is an astrisk or a plus.  If so then we must not use this
  318.            ;; character in the big literal.
  319.            (progn 
  320.          (if (or (eql term #\*) (eql term #\+))
  321.              (setf lit (subseq lit 0 (1- (length lit)))))
  322.          (add-exp `((if (< length (+ index ,(length lit)))
  323.                 (return-from compare nil))
  324.                 (if (not (,(if case-sensitive 'string= 'string-equal)
  325.                       string ,lit :start1 index
  326.                           :end1 (+ index ,(length lit))))
  327.                 (return-from compare nil)
  328.                   (incf index ,(length lit)))))))
  329.          (incf eindex (1- (length lit))))))))
  330.     ;;
  331.     ;; Plug end of list to return t.  If we made it this far then
  332.     ;; We have matched!
  333.     (add-exp '((setf (cadr (aref *regex-groups* 0))
  334.              index)))
  335.     (add-exp '((return-from final-return t)))
  336.     ;;
  337. ;;;    (print expression)
  338.     ;;
  339.     ;; Now take the expression list and turn it into a lambda expression
  340.     ;; replacing the special flags with lisp code.
  341.     ;; For example:  A BEGIN needs to be replace by an expression that
  342.     ;; saves the current index, then evaluates everything till it gets to
  343.     ;; the END then save the new index if it didn't fail.
  344.     ;; On an ASTRISK I need to take the previous expression and wrap
  345.     ;; it in a do that will evaluate the expression till an error
  346.     ;; occurs and then another do that encompases the remainder of the
  347.     ;; regular expression and iterates decrementing the index by one
  348.     ;; of the matched expression sizes and then returns nil.  After
  349.     ;; the last expression insert a form that does a return t so that
  350.     ;; if the entire nested sub-expression succeeds then the loop
  351.     ;; is broken manually.
  352.     ;; 
  353.     (setf result (copy-tree nil))
  354.     ;;
  355.     ;; Reversing the current expression makes building up the 
  356.     ;; lambda list easier due to the nexting of expressions when 
  357.     ;; and astrisk has been encountered.
  358.     (setf expression (reverse expression))
  359.     (do ((elt 0 (1+ elt)))
  360.     ((>= elt (length expression)))
  361.       (let ((piece (nth elt expression)))
  362.     ;;
  363.     ;; Now check for PLUS, if so then ditto the expression and then let the
  364.     ;; ASTRISK below handle the rest.
  365.     ;;
  366.     (cond ((eql piece 'PLUS)
  367.            (cond ((listp (nth (1+ elt) expression))
  368.               (setf result (append (list (nth (1+ elt) expression))
  369.                        result)))
  370.              ;;
  371.              ;; duplicate the entire group
  372.              ;; NOTE: This hasn't been implemented yet!!
  373.              (t
  374.               (format *standard-output* "GROUP repeat hasn't been implemented yet~%")))))
  375.     (cond ((listp piece)        ;Just append the list
  376.            (setf result (append (list piece) result)))
  377.           ((eql piece 'QUESTION)    ; Wrap it in a block that won't fail
  378.            (cond ((listp (nth (1+ elt) expression))
  379.               (setf result 
  380.                 (append `((progn (block compare
  381.                             ,(nth (1+ elt) 
  382.                               expression))
  383.                          t))
  384.                     result))
  385.               (incf elt))
  386.              ;;
  387.              ;; This is a QUESTION on an entire group which
  388.              ;; hasn't been implemented yet!!!
  389.              ;;
  390.              (t
  391.               (format *standard-output* "Optional groups not implemented yet~%"))))
  392.           ((or (eql piece 'ASTRISK) ; Do the wild thing!
  393.            (eql piece 'PLUS))
  394.            (cond ((listp (nth (1+ elt) expression))
  395.               ;;
  396.               ;; This is a single character wild card so
  397.               ;; do the simple form.
  398.               ;;
  399.               (setf result 
  400.                 `((let ((oindex index))
  401.                 (declare (fixnum oindex))
  402.                 (block compare
  403.                        (do ()
  404.                        (nil)
  405.                      ,(nth (1+ elt) expression)))
  406.                 (do ((start index (1- start)))
  407.                     ((< start oindex) nil)
  408.                   (declare (fixnum start))
  409.                   (let ((index start))
  410.                     (declare (fixnum index))
  411.                     (block compare
  412.                        ,@result))))))
  413.               (incf elt))
  414.              (t
  415.               ;;
  416.               ;; This is a subgroup repeated so I must build
  417.               ;; the loop using several values.
  418.               ;;
  419.               ))
  420.            )
  421.           (t t))))            ; Just ignore everything else.
  422.     ;;
  423.     ;; Now wrap the result in a lambda list that can then be 
  424.     ;; invoked or compiled, however the user wishes.
  425.     ;;
  426.     (if anchored
  427.     (setf result
  428.           `(lambda (string &key (start 0) (end (length string)))
  429.          (declare (string string)
  430.               (fixnum start end)
  431.               (optimize (speed 0) (compilation-speed 3)))
  432.          (setf *regex-groupings* ,group)
  433.          (block final-return
  434.             (block compare
  435.                    (let ((index start)
  436.                      (length end))
  437.                  (declare (fixnum index length))
  438.                  ,@result)))))
  439.       (setf result
  440.         `(lambda (string &key (start 0) (end (length string)))
  441.            (declare (string string)
  442.             (fixnum start end)
  443.             (optimize (speed 0) (compilation-speed 3)))
  444.            (setf *regex-groupings* ,group)
  445.            (block final-return
  446.               (let ((length end))
  447.             (declare (fixnum length))
  448.             ,@fast-first
  449.             (do ((marker start (1+ marker)))
  450.                 ((> marker end) nil)
  451.               (declare (fixnum marker))
  452.               (let ((index marker))
  453.                 (declare (fixnum index))
  454.                 (if (block compare
  455.                        ,@result)
  456.                 (return t)))))))))))
  457.  
  458.  
  459. ;;;
  460. ;;; Define a function that will take a quoted character and return
  461. ;;; what the real character should be plus how much of the source
  462. ;;; string was used.  If the result is a set of characters, return an
  463. ;;; array of bits indicating which characters should be set.  If the
  464. ;;; expression is one of the sub-group matches return a
  465. ;;; list-expression that will provide the match.  
  466. ;;;
  467. (defun regex-quoted (char-string &optional (invert nil))
  468.   "Usage: (regex-quoted <char-string> &optional invert)
  469.        Returns either the quoted character or a simple bit vector of bits set for
  470.        the matching values"
  471.   (let ((first (char char-string 0))
  472.     (result (char char-string 0))
  473.     (used-length 1))
  474.     (cond ((eql first #\n)
  475.        (setf result #\NewLine))
  476.       ((eql first #\c)
  477.        (setf result #\Return))
  478.       ((eql first #\t)
  479.        (setf result #\Tab))
  480.       ((eql first #\d)
  481.        (setf result #*0000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
  482.       ((eql first #\D)
  483.        (setf result #*1111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
  484.       ((eql first #\w)
  485.        (setf result #*0000000000000000000000000000000000000000000000001111111111000000011111111111111111111111111000010111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
  486.       ((eql first #\W)
  487.        (setf result #*1111111111111111111111111111111111111111111111110000000000111111100000000000000000000000000111101000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
  488.       ((eql first #\b)
  489.        (setf result #*0000000001000000000000000000000011000000000010100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
  490.       ((eql first #\B)
  491.        (setf result #*1111111110111111111111111111111100111111111101011111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
  492.       ((eql first #\s)
  493.        (setf result #*0000000001100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
  494.       ((eql first #\S)
  495.        (setf result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
  496.       ((and (>= (char-code first) (char-code #\0))
  497.         (<= (char-code first) (char-code #\9)))
  498.        (if (and (> (length char-string) 2)
  499.             (and (>= (char-code (char char-string 1)) (char-code #\0))
  500.              (<= (char-code (char char-string 1)) (char-code #\9))
  501.              (>= (char-code (char char-string 2)) (char-code #\0))
  502.              (<= (char-code (char char-string 2)) (char-code #\9))))
  503.            ;;
  504.            ;; It is a single character specified in octal
  505.            ;;
  506.            (progn 
  507.          (setf result (do ((x 0 (1+ x))
  508.                    (return 0))
  509.                   ((= x 2) return)
  510.                 (setf return (+ (* return 8)
  511.                         (- (char-code (char char-string x))
  512.                            (char-code #\0))))))
  513.          (setf used-length 3))
  514.          ;;
  515.          ;; We have a group number replacement.
  516.          ;;
  517.          (let ((group (- (char-code first) (char-code #\0))))
  518.            (setf result `((let ((nstring (subseq string (car (aref *regex-groups* ,group))
  519.                              (cadr (aref *regex-groups* ,group)))))
  520.                 (if (< length (+ index (length nstring)))
  521.                     (return-from compare nil))
  522.                 (if (not (string= string nstring
  523.                           :start1 index
  524.                           :end1 (+ index (length nstring))))
  525.                     (return-from compare nil)
  526.                   (incf index (length nstring)))))))))
  527.       (t 
  528.        (setf result first)))
  529.     (if (and (vectorp result) invert)
  530.     (bit-xor result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 t))
  531.     (values result used-length)))
  532.  
  533.